﻿using Kimd.Common;
using Kimd.Communication;
using Kimd.Motion;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kimd.Machine
{

    public class MotionFactory : SingletonProvider<MotionFactory>
    {
        private ModelHelper<ICard> _cardOperators;
        private ModelHelper<IAxis> _axisOperators;
        private ModelHelper<ICoordinate> _coordinateOperators;
        private ModelHelper<IDigitalIO> _digitalOperators;
        private ModelHelper<IPdo> _pdoOperators;
        public List<string> CardTypes { get; private set; } = new List<string>();

        public void GetCardTypes()
        {
            CardTypes.Clear();
            List<string> cardType = new List<string>();
            cardType.AddRange(_cardOperators.ModelInstances.Keys.ToList());
            cardType.AddRange(_axisOperators.ModelInstances.Keys.ToList());
            cardType.AddRange(_digitalOperators.ModelInstances.Keys.ToList());
            cardType.AddRange(_coordinateOperators.ModelInstances.Keys.ToList());
            cardType.ForEach(o =>
            {
                CardTypes.Add(o.Replace("CardOperator", "").Replace("AxisOperator", "").Replace("CoordinateOperator", "")
                    .Replace("DigitalOperator", "").Replace("InfoOperator", ""));
            });
            CardTypes = CardTypes.Distinct().ToList();
        }
        public void UpdateCard(ControlCard father, string cardType)
        {
            father.CardOperator = _cardOperators.ModelInstances.FirstOrDefault(kvp => kvp.Key.Contains($"{cardType}CardOperator")).Value;
            father.AxisOperator = _axisOperators.ModelInstances.FirstOrDefault(kvp => kvp.Key.Contains($"{cardType}AxisOperator")).Value;
            father.CoordinateOperator = _coordinateOperators.ModelInstances.FirstOrDefault(kvp => kvp.Key.Contains($"{cardType}CoordinateOperator")).Value;
            father.DigitalOperator = _digitalOperators.ModelInstances.FirstOrDefault(kvp => kvp.Key.Contains($"{cardType}DigitalOperator")).Value;
        }
        public void InitializeMotion(MachineResource machineResource)
        {
            if (machineResource.MachineCard == null)
                machineResource.MachineCard = new SerializableDictionary<string, ControlCard>();
            if (machineResource.MachineSensor == null)
                machineResource.MachineSensor = new SerializableDictionary<string, Sensor>();
            if (machineResource.MachineCylinder == null)
                machineResource.MachineCylinder = new SerializableDictionary<string, Cylinder>();
            if (machineResource.MachineAxis == null)
                machineResource.MachineAxis = new SerializableDictionary<string, Axis>();
            _cardOperators = new ModelHelper<ICard>();
            _cardOperators.LoadTypes("MotionLibs");
            _cardOperators.LoadInstances();
            _axisOperators = new ModelHelper<IAxis>();
            _axisOperators.LoadTypes("MotionLibs");
            _axisOperators.LoadInstances();
            _coordinateOperators = new ModelHelper<ICoordinate>();
            _coordinateOperators.LoadTypes("MotionLibs");
            _coordinateOperators.LoadInstances();
            _digitalOperators = new ModelHelper<IDigitalIO>();
            _digitalOperators.LoadTypes("MotionLibs");
            _digitalOperators.LoadInstances();
            _pdoOperators = new ModelHelper<IPdo>();
            _pdoOperators.LoadTypes("MotionLibs");
            _pdoOperators.LoadInstances();
            GetCardTypes();
            ModelHelper<ControlCard> cardTypeOperator = new ModelHelper<ControlCard>();
            cardTypeOperator.LoadTypes("MotionLibs");

            if (machineResource.MachineCard != null && machineResource.MachineCard.Count > 0)
            {
                foreach (KeyValuePair<string, ControlCard> card in machineResource.MachineCard)
                {
                    card.Value.CardOperator = _cardOperators.ModelInstances.FirstOrDefault(kvp => kvp.Key.Contains($"{card.Value.CardType}CardOperator")).Value;
                    card.Value.AxisOperator = _axisOperators.ModelInstances.FirstOrDefault(kvp => kvp.Key.Contains($"{card.Value.CardType}AxisOperator")).Value;
                    card.Value.CoordinateOperator = _coordinateOperators.ModelInstances.FirstOrDefault(kvp => kvp.Key.Contains($"{card.Value.CardType}CoordinateOperator")).Value;
                    card.Value.DigitalOperator = _digitalOperators.ModelInstances.FirstOrDefault(kvp => kvp.Key.Contains($"{card.Value.CardType}DigitalOperator")).Value;
                    card.Value.PdoOperator = _pdoOperators.ModelInstances.FirstOrDefault(kvp => kvp.Key.Contains($"{card.Value.CardType}PdoOperator")).Value;
                }
            }
        }
        public void InitializeMotion2(MachineResource machineResource)
        {
            if (machineResource.MachineAxis != null && machineResource.MachineAxis.Count > 0)
            {
                foreach (KeyValuePair<string, Axis> axis in machineResource.MachineAxis)
                {
                    if (machineResource.MachineCard.Keys.Contains(axis.Value.ControlCardName))
                    {
                        axis.Value.Card = machineResource.MachineCard[axis.Value.ControlCardName];
                    }
                    else
                        axis.Value.Card = null;
                }
            }
            if (machineResource.MachineSensor != null && machineResource.MachineSensor.Count > 0)
            {
                foreach (KeyValuePair<string, Sensor> sensor in machineResource.MachineSensor)
                {
                    if (machineResource.MachineCard.Keys.Contains(sensor.Value.ControlCardName))
                    {
                        sensor.Value.Card = machineResource.MachineCard[sensor.Value.ControlCardName];
                    }
                    else
                        sensor.Value.Card = null;
                }
            }
            if (machineResource.MachineCylinder != null && machineResource.MachineCylinder.Count > 0)
            {
                foreach (KeyValuePair<string, Cylinder> cylinder in machineResource.MachineCylinder)
                {
                    if (machineResource.MachineCard.Keys.Contains(cylinder.Value.ControlCardName1))
                    {
                        cylinder.Value.Card1 = machineResource.MachineCard[cylinder.Value.ControlCardName1];
                    }
                    else
                        cylinder.Value.Card1 = null;

                    if (!string.IsNullOrEmpty(cylinder.Value.ID2))
                    {
                        if (machineResource.MachineCard.Keys.Contains(cylinder.Value.ControlCardName2))
                        {
                            cylinder.Value.Card2 = machineResource.MachineCard[cylinder.Value.ControlCardName2];
                        }
                        else
                            cylinder.Value.Card2 = null;
                    }
                    else
                        cylinder.Value.Card2 = null;
                    cylinder.Value.Origins.Clear();
                    cylinder.Value.Moves.Clear();
                    foreach (var item in cylinder.Value.OriginNames)
                    {
                        if (machineResource.MachineSensor.Keys.Contains(item))
                            cylinder.Value.Origins.Add(machineResource.MachineSensor[item]);
                    }
                    foreach (var item in cylinder.Value.MoveNames)
                    {
                        if (machineResource.MachineSensor.Keys.Contains(item))
                            cylinder.Value.Moves.Add(machineResource.MachineSensor[item]);
                    }
                }
            }
            if (machineResource.MachinePdo != null && machineResource.MachinePdo.Count > 0)
            {
                foreach (KeyValuePair<string, Pdo> pdo in machineResource.MachinePdo)
                {
                    if (machineResource.MachineCard.Keys.Contains(pdo.Value.ControlCardName))
                    {
                        pdo.Value.Card = machineResource.MachineCard[pdo.Value.ControlCardName];
                    }
                    else
                        pdo.Value.Card = null;
                }
            }
        }
        public void InitializeLimit(MachineResource machineResource)
        {
            MotionLimit.Init(machineResource.MachineAxis, machineResource.MachineSensor);
            PositionLimit.Init(machineResource.MachineAxis, machineResource.MachineSensor);
            SensorLimit.Init(machineResource.MachineAxis, machineResource.MachineSensor);
            foreach (Axis axis in machineResource.MachineAxis.Values)
            {
                foreach (var ml in axis.AxisLimits)
                {
                    ml.SetAxis(axis);
                }
                foreach (var pl in axis.PositionLimits)
                {
                    pl.SetAxis(axis);
                }
                foreach (var sl in axis.SensorLimits)
                {
                    sl.SetAxis(axis);   
                }
            }
        }
        public void InitializeTray(MachineResource machineResource)
        {
            foreach (Axis axis in MachineResource.Instance.MachineAxis.Values)
            {
                foreach (KeyValuePair<string, SerializableDictionary<string, Tray>> item in MachineResource.Instance.ModuleTrays)
                {
                    if (item.Key.Equals(axis.Module))
                    {
                        axis.MotionTray.Clear();
                        foreach (var item2 in item.Value)
                        {
                            List<string> names = axis.MotionPosition.Keys.ToList();
                            List<double> positions = axis.MotionPosition.Values.ToList();
                            List<string> allRemoveNames = new List<string>();
                            foreach (var p in axis.MotionPosition)
                            {
                                if (p.Key.Contains(item2.Key))
                                {
                                    allRemoveNames.Add(p.Key);
                                }
                            }
                            allRemoveNames.ForEach(name => axis.MotionPosition.Remove(name));
                            item2.Value.Helper.Calibrate();
                            axis.MotionTray.Add(item2.Key, item2.Value);
                            if(axis.Description.Equals(item2.Value.XAxisName))
                            {
                                for (int i = 0; i < item2.Value.RowCount * item2.Value.ColCount; i++)
                                {
                                    for (int j = 0; j < item2.Value.NozzleCount; j++)
                                    {
                                        axis.MotionPosition.Add($"{item2.Key}-{i}-{j}", item2.Value.Helper.GetPoint(i).X + j * item2.Value.OffsetX);
                                    }
                                }
                            }
                            else if (axis.Description.Equals(item2.Value.YAxisName))
                            {
                                for (int i = 0; i < item2.Value.RowCount * item2.Value.ColCount; i++)
                                {
                                    for (int j = 0; j < item2.Value.NozzleCount; j++)
                                    {
                                        axis.MotionPosition.Add($"{item2.Key}-{i}-{j}", item2.Value.Helper.GetPoint(i).Y + j * item2.Value.OffsetY);
                                    }
                                }
                            }
                            else if (axis.Description.Equals(item2.Value.ZAxisName))
                            {
                                for (int i = 0; i < item2.Value.RowCount * item2.Value.ColCount; i++)
                                {
                                    for (int j = 0; j < item2.Value.NozzleCount; j++)
                                    {
                                        axis.MotionPosition.Add($"{item2.Key}-{i}-{j}", item2.Value.Helper.GetZ());
                                    }
                                }
                            }
                            else if (axis.Description.Equals(item2.Value.RAxisName))
                            {
                                for (int i = 0; i < item2.Value.RowCount * item2.Value.ColCount; i++)
                                {
                                    for (int j = 0; j < item2.Value.NozzleCount; j++)
                                    {
                                        axis.MotionPosition.Add($"{item2.Key}-{i}-{j}", item2.Value.Helper.GetR());
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        public void InitializeAxis(MachineResource machineResource, Axis axis)
        {
            if (machineResource.MachineCard.Keys.Contains(axis.ControlCardName))
            {
                axis.Card = machineResource.MachineCard[axis.ControlCardName];
            }
            else
                axis.Card = null;
        }
        public void InitializeSensor(MachineResource machineResource, Sensor sensor)
        {
            if (machineResource.MachineCard.Keys.Contains(sensor.ControlCardName))
            {
                sensor.Card = machineResource.MachineCard[sensor.ControlCardName];
            }
            else
                sensor.Card = null;
        }
        public void InitializeCylinder(MachineResource machineResource, Cylinder cylinder)
        {
            if (machineResource.MachineCard.Keys.Contains(cylinder.ControlCardName1))
            {
                cylinder.Card1 = machineResource.MachineCard[cylinder.ControlCardName1];
            }
            else
                cylinder.Card1 = null;

            if (!string.IsNullOrEmpty(cylinder.ID2))
            {
                if (machineResource.MachineCard.Keys.Contains(cylinder.ControlCardName2))
                {
                    cylinder.Card2 = machineResource.MachineCard[cylinder.ControlCardName2];
                }
                else
                    cylinder.Card2 = null;
            }
            else
                cylinder.Card2 = null;
            cylinder.Origins.Clear();
            cylinder.Moves.Clear();
            foreach (var item in cylinder.OriginNames)
            {
                if (machineResource.MachineSensor.Keys.Contains(item))
                    cylinder.Origins.Add(machineResource.MachineSensor[item]);
            }
            foreach (var item in cylinder.MoveNames)
            {
                if (machineResource.MachineSensor.Keys.Contains(item))
                    cylinder.Moves.Add(machineResource.MachineSensor[item]);
            }
        }
        public void InitializePLC(MachineResource machineResource)
        {
           
            foreach (PLCOperator pLC in machineResource.MachinePLC.Values)
            {
                switch(pLC.Brand)
                {
                    case "Inovance":
                        InovancePLCOperator inovancePLC = new InovancePLCOperator();
                        pLC.SetOperator(inovancePLC);
                        break;
                }
            }
        }
    }
}
